package mail

import (
	"bytes"
	"fmt"
	"io"
	"niu-ren/utils/common"
	"sync"
	"time"

	"github.com/emersion/go-imap"
	imap_id "github.com/emersion/go-imap-id"
	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-message"
	"github.com/emersion/go-message/charset"
	"github.com/emersion/go-message/mail"
)

type MailClient struct {
	IMailboxMsgCb
	config *Config
	*client.Client
	conStat          ConnState
	sLock            *sync.RWMutex
	stopWatchMailbox chan struct{}
	stopStatusUpdate chan struct{}
	stopWatchLogout  chan struct{}
	triggerCbCh      chan *listenData
	updateMonitor    chan client.Update
	curMailboxStatus *imap.MailboxStatus
}

type MsgBody struct {
	Msg       *imap.Message
	MsgHeader *mail.Header
	BodyPart  []struct {
		PartType   BodyPart
		PartBody   io.Reader
		PartHeader mail.PartHeader
	}
}

func defaultConfig(mc *MailClient) {
	mc.config.isOn = true
	mc.config.enableMailboxWatch = true
	mc.config.cmdTimeout = mc.GetCmdTimeout()
	mc.stopStatusUpdate = make(chan struct{}, 1)
	mc.stopWatchLogout = make(chan struct{}, 1)
	mc.config.updateMailboxStatusInterval = 30 * time.Second
}

func NewMailClient(cfgs ...Option) (*MailClient, error) {
	mc := &MailClient{config: new(Config)}
	defaultConfig(mc)
	for _, cfg := range cfgs {
		cfg(mc)
	}
	mc.config.curMailbox =
		IfStr(mc.config.curMailbox == "", DEFAULTMAILBOX, mc.config.curMailbox)
	mc.initTriggerCbCh()
	c, err := mc.ConnectToServer()
	if err != nil {
		return nil, err
	}
	mc.Client = c
	mc.checkDebugMode()
	mc.WacthServerConn()
	mc.UpdateMailboxStatus()
	mc.sLock = new(sync.RWMutex)
	imap.CharsetReader = charset.Reader
	if mc.config.isOn && mc.config.enableMailboxWatch {
		mc.cbListening()
		if !mc.IsIDLESupported() && mc.config.pollingInterval < 0 {
			return mc, mc.SelectMailBox(false, mc.config.curMailbox)
		}
		return mc, mc.LaunchMailboxWatching()
	}
	return mc, mc.SelectMailBox(false, mc.config.curMailbox)
}

func (mc *MailClient) Logout(stat ...ConnState) error {
	mc.SetConnStat(append(stat, DISCONNECT)[0])
	mc.CloseWatchCh()
	return mc.GetClient().Logout()
}

func (mc *MailClient) LogoutWithoutDisConnect(stat ...ConnState) error {
	mc.SetConnStat(append(stat, DISCONNECT)[0])
	mc.CloseWatchCh()
	return nil
}

func (mc *MailClient) ReConn() error {
	defer common.RecoverPanic()
	fmt.Printf("%s: reconnecting ... \n", mc.GetConfig().account)
	c, err := mc.ConnectToServer()
	if err != nil {
		fmt.Printf("reconn fail:%v\n", err)
		return err
	}
	mc.Client = c
	mc.checkDebugMode()
	mc.StopWatchLogout()
	mc.SetWatchLogout()
	mc.WacthServerConn()
	if mc.GetConfig().enableMailboxWatch {
		if !mc.IsIDLESupported() && mc.GetConfig().pollingInterval < 0 {
			return mc.SelectMailBox(false, mc.GetConfig().curMailbox)
		}
		return mc.LaunchMailboxWatching()
	}
	if err == mc.SelectMailBox(false, mc.GetConfig().curMailbox) {
		fmt.Printf("reconnection done\n")
	}
	return err
}

func (mc *MailClient) StopWatchLogout() {
	close(mc.stopWatchLogout)
}

func (mc *MailClient) SetWatchLogout() {
	mc.stopWatchLogout = make(chan struct{}, 1)
}

func (mc *MailClient) LaunchMailboxWatching() error {
	err := mc.mailBoxWatching(
		mc.GetConfig().watchMailboxTimeout, mc.GetConfig().pollingInterval, mc.GetConfig().curMailbox)
	if err == nil {
		time.Sleep(time.Second) // wait to launche op done.
		fmt.Printf("launching mailbox %s watching done!\n", mc.GetConfig().account)
	}
	return err
}

func (mc *MailClient) StopMailboxWatching() {
	defer RecoverPanic()
	defer time.Sleep(time.Second) // wait to close operation done.
	if mc.stopWatchMailbox != nil {
		close(mc.stopWatchMailbox)
	}
}

func (mc *MailClient) CloseWatchCh() {
	defer RecoverPanic()
	mc.updateMonitor = nil
	if mc.stopWatchMailbox != nil {
		close(mc.stopWatchMailbox)
	}
}

func (mc *MailClient) ConnectToServer() (*client.Client, error) {
	var err error
	var c *client.Client
	fmt.Printf("%s: imap server connecting ...\n", mc.GetConfig().account)
	switch {
	default:
		c, err = client.Dial(mc.GetConfig().serverAddr)
	case mc.GetConfig().sslEncrypt:
		c, err = client.DialTLS(mc.GetConfig().serverAddr, nil)
	}
	if err != nil {
		fmt.Printf("server address %s of %s connection exception:%v\n", mc.GetConfig().serverAddr, mc.GetConfig().account, err)
		return nil, err
	}
	_, err = imap_id.NewClient(c).ID(
		imap_id.ID{imap_id.FieldName: "nr-IMAPClient_" + common.Int64ToString(time.Now().UnixNano()), imap_id.FieldVersion: "1.0.0"},
	)
	if err != nil {
		fmt.Printf("sending ID command to server for getting server's ID exception:%v\n", err)
		return nil, err
	}
	err = c.Login(mc.GetConfig().account,
		IfStr(mc.GetConfig().authCode != "", mc.GetConfig().authCode, mc.GetConfig().password))
	if err != nil {
		fmt.Printf("loginning to imap server exception:%v\n", err)
		return nil, err
	}
	mc.SetConnStat(CONNECTED)
	fmt.Printf("%s: imap server connection done\n", mc.GetConfig().account)
	return c, nil
}

func (mc *MailClient) mailBoxWatching(watchTimeout, pollingInterval time.Duration, mailbox ...string) error {
	var err error
	fmt.Printf("%s: launching mailbox watching!\n", mc.GetConfig().account)
	if err != mc.SelectMailBox(false, mailbox...) {
		fmt.Printf("selecting mailBox fail:%v\n", err)
		return err
	}
	go func() {
		defer RecoverPanic()
		exitWatchRsp := make(chan error, 1)
		mc.stopWatchMailbox = make(chan struct{})
		mc.updateMonitor = make(chan client.Update, 100)
		go func() {
			defer RecoverPanic()
			c, err := mc.ConnectToServer()
			if err != nil {
				panic(fmt.Sprintf("Connecting to server for mailbox watching fail:%v\n", err))
			}
			defer c.Logout()
			c.Updates = mc.updateMonitor
			c.Select(append(mailbox, DEFAULTMAILBOX)[0], false)
			exitWatchRsp <- c.Idle(mc.stopWatchMailbox, &client.IdleOptions{
				LogoutTimeout: watchTimeout,
				PollInterval:  pollingInterval,
			})
		}()
		for {
			select {
			case e := <-exitWatchRsp:
				if e != nil && e != client.ErrExtensionUnsupported {
					fmt.Printf("watching mailbox exception:%v\n", e)
					if mc.GetConnStat() == CONNECTED {
						mc.Logout()
					}
					fmt.Printf("out of idle blocking ...\n")
					return
				}
				fmt.Printf("mailbox watching stopped.Launching it again later,if it's Necessary! \n")
				return
			case iu := <-mc.updateMonitor:
				go func(iU client.Update) {
					defer RecoverPanic()
					mc.updatesHandle(iU)
				}(iu)
			}
		}
	}()
	return nil
}

func (mc *MailClient) updatesHandle(iu client.Update) {
	if mc.GetClient().State() == imap.LogoutState || mc.GetConnStat() != CONNECTED {
		return
	}
	switch uType := iu.(type) {
	case *client.ExpungeUpdate:
		mc.TriggerCb(&listenData{dataType: uType})
		fmt.Printf("%s %v: message %d deleted\n", mc.GetConfig().account, time.Now(), uType.SeqNum)
	case *client.MessageUpdate:
		fetchItems, _ := GetMapStrKeys(uType.Message.Items)
		fmt.Printf("%s %v: status of new message %d changed: %v\n", mc.GetConfig().account, time.Now(), uType.Message.SeqNum, fetchItems)
		mc.msgUpdateCb(uType, uType.Message)
	case *client.StatusUpdate:
		if uType.Status.Type == imap.StatusRespBye {
			fmt.Printf("%s %v: server is about to close connection\n", mc.GetConfig().account, time.Now())
			mc.Logout()
		}
		if uType.Status.Type == imap.StatusRespOk ||
			uType.Status.Type == imap.StatusRespNo ||
			uType.Status.Type == imap.StatusRespBad {
			fmt.Printf("%s %v: message from server about one associated cmd:%#v\n", mc.GetConfig().account, time.Now(), *uType.Status)
		}
		mc.TriggerCb(&listenData{dataType: uType})
	case *client.MailboxUpdate:
		var status imap.StatusItem
		if uType.Mailbox.Items[imap.StatusRecent] == nil {
			fmt.Printf("%s %v: The number of recent messages since the last time the mailbox %s was opened:%d\n",
				mc.GetConfig().account, time.Now(), uType.Mailbox.Name, uType.Mailbox.Recent)
			uType.Mailbox.Items[imap.StatusRecent] = uType.Mailbox.Recent
			status = imap.StatusRecent
		}
		if uType.Mailbox.Items[imap.StatusMessages] == nil {
			fmt.Printf("%s %v: messages num of mailbox %s: %d\n", mc.GetConfig().account, time.Now(), uType.Mailbox.Name, uType.Mailbox.Messages)
			uType.Mailbox.Items[imap.StatusMessages] = uType.Mailbox.Messages
			status = imap.StatusMessages
		}
		mc.TriggerCb(&listenData{value: status, dataType: uType})
	}
}

func (mc *MailClient) msgUpdateCb(uType *client.MessageUpdate, message *imap.Message) {
	go func(msg *imap.Message) {
		defer RecoverPanic()
		for item := range msg.Items {
			switch item {
			default:
				fmt.Printf("unhandled update item %v\n", item)
			case imap.FetchUid:
				fmt.Printf("uid of new msg %d:%d\n", msg.SeqNum, msg.Uid)
			case imap.FetchRFC822Size:
				fmt.Printf("size of new msg %d:%d\n", msg.SeqNum, msg.Size)
			case imap.FetchFlags:
				fmt.Printf("flags of new msg %d changed:\n", msg.SeqNum)
				mc.msgFlagsUpdate(msg)
			case imap.FetchEnvelope:
				fmt.Printf("envelope of new msg %d changed:%#v\n", msg.SeqNum, *msg.Envelope)
			case imap.FetchBody, imap.FetchBodyStructure:
				fmt.Printf("BodyStructure of new msg %d changed:%#v\n", msg.SeqNum, *msg.BodyStructure)
			case imap.FetchInternalDate:
				fmt.Printf("The date of new message was received by the server:%v\n", msg.InternalDate)
			}
		}
		mc.TriggerCb(&listenData{value: message, dataType: uType})
	}(message)
}

func (mc *MailClient) msgFlagsUpdate(msg *imap.Message) {
	for _, flag := range msg.Flags {
		switch flag {
		default:
			fmt.Printf("customed new msg flag:%s\n", flag)
		case imap.SeenFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.SeenFlag)
		case imap.DraftFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.DraftFlag)
		case imap.RecentFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.RecentFlag)
		case imap.FlaggedFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.FlaggedFlag)
		case imap.AnsweredFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.AnsweredFlag)
		case imap.DeletedFlag:
			// todo
			fmt.Printf("new msg was flaged as %s\n", imap.DeletedFlag)
		}
	}
}

func (mc *MailClient) WacthServerConn() {
	go func() {
		defer RecoverPanic()
		select {
		case <-mc.stopWatchLogout:
			fmt.Printf("%smail server stop watch logout:%s %s\n", SEPERATION, mc.GetConfig().account, SEPERATION)
			break
		case <-mc.GetClient().LoggedOut():
			fmt.Printf("%smail server disconnect with client:%s %s\n", SEPERATION, mc.GetConfig().account, SEPERATION)
			if mc.GetConnStat() == SHUTDOWN {
				return
			}
			time.AfterFunc(3*time.Second, func() {
				defer RecoverPanic()
				for i := 0; i < 3; i++ {
					if err := mc.ReConn(); err != nil {
						fmt.Printf("reconn exception:%v\n", err)
						time.Sleep(3 * time.Second)
						continue
					}
					break
				}
			})
		}
	}()
}

func (mc *MailClient) MailBoxLists(ref, name string) ([]*imap.MailboxInfo, error) {
	done := make(chan error, 1)
	boxs := []*imap.MailboxInfo{}
	mailboxes := make(chan *imap.MailboxInfo, 10)
	go func() {
		defer RecoverPanic()
		done <- mc.GetClient().List(ref, name, mailboxes)
	}()
	t := time.After(10 * time.Second)
LOOP:
	for {
		select {
		case m, ok := <-mailboxes:
			if !ok {
				fmt.Printf("all mailbox list fetched\n")
				break LOOP
			}
			boxs = append(boxs, m)
		case <-t:
			fmt.Printf("fetching mailbox list timeout\n")
			break LOOP
		}
	}
	for _, m := range boxs {
		fmt.Println("mailbox list:" + "* " + m.Name)
	}
	t = time.After(10 * time.Second)
	select {
	case err := <-done:
		if err != nil {
			fmt.Printf("fetching mailbox list fail:%v\n", err)
		}
		return boxs, err
	case <-t:
		fmt.Printf("waitting to fetch mailbox list,but timeout\n")
		return boxs, fmt.Errorf("waitting to fetch mailbox list,but timeout\n")
	}
}

func (mc *MailClient) checkDebugMode() {
	if mc.GetConfig().debugMode {
		mc.WatchNetwork(mc.GetConfig().debugOut)
	}
}

func (mc *MailClient) EnableMailboxExtension(exts []Extension) ([]string, error) {
	extStrs := []string{}
	for _, e := range exts {
		extStrs = append(extStrs, string(e))
	}
	return mc.GetClient().Enable(extStrs)
}

func (mc *MailClient) CopyMsgToTargetMaibox(sourceSeqset *imap.SeqSet, targetMailbox string) error {
	return mc.GetClient().Copy(sourceSeqset, targetMailbox)
}

func (mc *MailClient) CopyMsgToTargetMaiboxByUid(sourceUid *imap.SeqSet, targetMailbox string) error {
	return mc.GetClient().UidCopy(sourceUid, targetMailbox)
}

func (mc *MailClient) MoveMsgToTargetMaibox(sourceSeqset *imap.SeqSet, targetMailbox string) error {
	return mc.GetClient().Move(sourceSeqset, targetMailbox)
}

func (mc *MailClient) MoveMsgToTargetMaiboxByUid(sourceUid *imap.SeqSet, targetMailbox string) error {
	return mc.GetClient().UidMove(sourceUid, targetMailbox)
}

func (mc *MailClient) ChangeCurMailbox(mailbox string, readOnly bool) (*imap.MailboxStatus, error) {
	return mc.GetMailboxStatus(), mc.SelectMailBox(readOnly, mailbox)
}

func (mc *MailClient) FreeMailbox() error {
	return mc.GetClient().Unselect()
}

func (mc *MailClient) ServerCapcity() (map[string]bool, error) {
	return mc.GetClient().Capability()
}

func (mc *MailClient) CkServerCapcity(capability string) (bool, error) {
	return mc.GetClient().Support(capability)
}

func (mc *MailClient) GetCurMailbox() *imap.MailboxStatus {
	return mc.GetClient().Mailbox()
}

func (mc *MailClient) NewMailbox(mailbox string) error {
	return mc.GetClient().Create(mailbox)
}

func (mc *MailClient) DelMailbox(mailbox string) error {
	return mc.GetClient().Delete(mailbox)
}

func (mc *MailClient) RemoveMsgWithDelFlag(ch chan uint32) error {
	return mc.GetClient().Expunge(ch)
}

func (mc *MailClient) RenameMailbox(oldName, newName string) error {
	return mc.GetClient().Rename(oldName, newName)
}

func (mc *MailClient) WatchNetwork(w io.Writer) { // -----
	mc.GetClient().SetDebug(w)
}

func (mc *MailClient) FetchMailboxStatus(mailbox string, items []imap.StatusItem) (*imap.MailboxStatus, error) { // -----
	return mc.GetClient().Status(mailbox, items)
}

func (mc *MailClient) AlterMessageStat(seqset *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error { // -----
	return mc.GetClient().Store(seqset, item, value, ch)
}

func (mc *MailClient) AlterMessageStatByUid(sourceUid *imap.SeqSet, item imap.StoreItem, value interface{}, ch chan *imap.Message) error { // -----
	return mc.GetClient().UidStore(sourceUid, item, value, ch)
}

func (mc *MailClient) FetchMsgManually(seqset *imap.SeqSet, items []imap.FetchItem) ([]*imap.Message, error) { // -----
	msgs := []*imap.Message{}
	messages := make(chan *imap.Message, 10)
	done := make(chan error, 1)
	go func() {
		defer RecoverPanic()
		done <- mc.GetClient().Fetch(seqset, items, messages)
	}()
	t := time.After(time.Minute)
LOOP:
	for {
		select {
		case m, ok := <-messages:
			if !ok {
				fmt.Printf("%s all message fetched\n", mc.GetConfig().account)
				break LOOP
			}
			msgs = append(msgs, m)
		case <-t:
			fmt.Printf("%s fetching message timeout\n", mc.GetConfig().account)
			break LOOP
		}
	}
	t = time.After(10 * time.Second)
	select {
	case err := <-done:
		if err != nil {
			fmt.Printf("%s fetching message fail:%v\n", mc.GetConfig().account, err)
		}
		return msgs, err
	case <-t:
		fmt.Printf("waitting to fetch message,but timeout\n")
		return msgs, fmt.Errorf("waitting to fetch message,but timeout\n")
	}
}

func (mc *MailClient) FetchMsgManuallyByUid(seqset *imap.SeqSet, items []imap.FetchItem) ([]*imap.Message, error) {
	msgs := []*imap.Message{}
	messages := make(chan *imap.Message, 10)
	done := make(chan error, 1)
	go func() {
		defer RecoverPanic()
		done <- mc.GetClient().UidFetch(seqset, items, messages)
	}()
	t := time.After(time.Minute)
LOOP:
	for {
		select {
		case m, ok := <-messages:
			if !ok {
				fmt.Printf("all message fetched\n")
				break LOOP
			}
			msgs = append(msgs, m)
		case <-t:
			fmt.Printf("fetching message timeout\n")
			break LOOP
		}
	}
	t = time.After(10 * time.Second)
	select {
	case err := <-done:
		if err != nil {
			fmt.Printf("fetching message by uid fail:%v\n", err)
		}
		return msgs, err
	case <-t:
		fmt.Printf("waitting to fetch message,but timeout\n")
		return msgs, fmt.Errorf("waitting to fetch message,but timeout\n")
	}
}

func (mc *MailClient) ParseMsgBody(messages []*imap.Message, section ...*imap.BodySectionName) ([]*MsgBody, error) {
	rsp := make([]*MsgBody, 0, len(messages))
	for _, msg := range messages {
		literal := msg.GetBody(append(section, new(imap.BodySectionName))[0])
		if literal == nil {
			fmt.Printf("no session msg found\n")
			continue
		}
		mr, err := mail.CreateReader(literal)
		if err != nil {
			fmt.Printf("reading literal msg exception:%v\n", err)
			continue
		}
		defer mr.Close()
		m := *msg
		header := mr.Header.Copy()
		oneMsgBody := &MsgBody{
			Msg:       &m,
			MsgHeader: &header,
			BodyPart: []struct {
				PartType   BodyPart
				PartBody   io.Reader
				PartHeader mail.PartHeader
			}{},
		}
		rsp = append(rsp, oneMsgBody)
		for {
			p, err := mr.NextPart()
			if err == io.EOF {
				break
			}
			if err != nil {
				// If the part uses an unknown transfer encoding or charset, NextPart returns an
				// error that verifies message.IsUnknownCharset, but also returns a Part that
				// can be used. So,continuing operation.
				if !message.IsUnknownCharset(err) && !message.IsUnknownEncoding(err) {
					fmt.Printf("reading body part exception:%v\n", err)
					break
				}
			}
			pT := INLINE
			buf := bytes.NewBuffer([]byte{})
			io.Copy(buf, p.Body)
			switch p.Header.(type) {
			case *mail.InlineHeader: // 正文
			case *mail.AttachmentHeader:
				pT = ATTCHMENT
			}
			oneMsgBody.BodyPart = append(oneMsgBody.BodyPart,
				struct {
					PartType   BodyPart
					PartBody   io.Reader
					PartHeader mail.PartHeader
				}{
					PartType:   pT,
					PartBody:   buf,
					PartHeader: p.Header,
				},
			)
		}
	}
	return rsp, nil
}

func (mc *MailClient) UpdateMailboxStatus() {
	if !mc.GetConfig().enableMailboxStatusUpdate {
		return
	}
	go func() {
		defer RecoverPanic(func(err interface{}) {
			mc.UpdateMailboxStatus()
		})
		randomInt, _ := GetRandomNum(0, 7)
		t := time.NewTicker(mc.GetConfig().updateMailboxStatusInterval + time.Duration(randomInt)*time.Second)
		defer t.Stop()
	LOOP:
		for {
			select {
			case <-mc.stopStatusUpdate:
				fmt.Printf("%s %s stop updating status %s\n", SEPERATION, mc.GetConfig().account, SEPERATION)
				break LOOP
			case <-t.C:
				fmt.Printf("update mailbox %s status ....\n", mc.GetConfig().account)
				status, err := mc.FetchMailboxStatus(mc.GetCurMailbox().Name, []imap.StatusItem{
					imap.StatusRecent,
					imap.StatusUnseen,
					imap.StatusMessages,
				})
				if err != nil {
					mc.curMailboxStatus = nil
					fmt.Printf("%s fetching mailbox %s status exception:%v %s\n", SEPERATION, mc.GetConfig().account, err, SEPERATION)
					continue
				}
				if err := mc.GetClient().Noop(); err != nil {
					fmt.Printf("%s mailbox %s no operation request exception:%v %s\n", SEPERATION, mc.GetConfig().account, err, SEPERATION)
					continue
				}
				mc.curMailboxStatus = status
				fmt.Printf("%s fetching mailbox %s status done %s\n", SEPERATION, mc.GetConfig().account, SEPERATION)
			}
		}
	}()
}

func (mc *MailClient) SearchMsg(criteria *imap.SearchCriteria) ([]uint32, error) { // -----
	return mc.GetClient().Search(criteria)
}

func (mc *MailClient) SearchMsgByUId(criteria *imap.SearchCriteria) ([]uint32, error) {
	return mc.GetClient().UidSearch(criteria)
}

func (mc *MailClient) GetClient() *client.Client {
	return mc.Client
}

func (mc *MailClient) GetConfig() *Config {
	return mc.config
}

func (mc *MailClient) SetConnStat(stat ConnState) {
	mc.conStat = stat
}

func (mc *MailClient) GetConnStat() ConnState {
	return mc.conStat
}

func (mc *MailClient) GetMailboxMsgCb() IMailboxMsgCb {
	return mc.IMailboxMsgCb
}

func (mc *MailClient) initTriggerCbCh() {
	mc.triggerCbCh = make(chan *listenData, 100)
}

func (mc *MailClient) GetTriggerCbCh() chan *listenData {
	return mc.triggerCbCh
}

func (mc *MailClient) GetMailboxStatus() *imap.MailboxStatus {
	return mc.curMailboxStatus
}

func (mc *MailClient) TriggerCb(data *listenData) {
	mc.GetTriggerCbCh() <- data
}

func (mc *MailClient) GetCmdTimeout() time.Duration {
	return 0
}

func (mc *MailClient) GetStopUpdateStatusCh() chan struct{} {
	return mc.stopStatusUpdate
}

func (mc *MailClient) IsIDLESupported() bool {
	if mc.GetClient() == nil {
		return false
	}
	ok, _ := mc.GetClient().Support("IDLE")
	return ok
}

func (mc *MailClient) SelectMailBox(readOnly bool, mailbox ...string) error {
	curMailboxStatus, err := mc.GetClient().Select(append(mailbox, DEFAULTMAILBOX)[0], readOnly)
	if err != nil {
		return err
	}
	mc.curMailboxStatus = curMailboxStatus
	return nil
}
